package cn.blnp.net.flowable.api.runtime;

import cn.hutool.core.date.DateUtil;
import liquibase.pro.packaged.M;
import lombok.extern.slf4j.Slf4j;
import org.flowable.engine.HistoryService;
import org.flowable.engine.RepositoryService;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.TaskService;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.repository.Deployment;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.engine.runtime.Execution;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.engine.runtime.ProcessInstanceBuilder;
import org.flowable.task.api.Task;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

import javax.annotation.Resource;
import java.util.Map;

/**
 * <h3>运行时服务API案例演示</h3>
 *
 * @author <a href="mailto:blnp.yibin@qq.com">lyb</a>
 * @version 1.0
 * @since 2025/4/29 11:22
 */
@Slf4j
@SpringBootTest
public class RuntimeApiTest {

    @Resource
    private RepositoryService repositoryService;
    @Resource
    private RuntimeService runtimeService;
    @Resource
    private TaskService taskService;
    @Resource
    private HistoryService historyService;

    /**
     *  <p>
     *      RuntimeService接口主要用于对Flowable中与流程运行时相关的数据进行操作，对应名称以ACT_RU_开头的相关运行时表。该接口提供的方法主要包括以下6类：
     *  </p>
     *  <hr/>
     *  <ul>
     *      <li>创建和发起流程实例；</li>
     *      <li>唤醒等待状态的流程实例；</li>
     *      <li>流程权限的管理，主要指流程实例和人员之间的关系管理，如流程参与人管理等；</li>
     *      <li>流程变量的管理，包括流程变量的新增、删除、查询等；</li>
     *      <li>管理运行时流程实例、执行实例、数据对象等运行时对象；</li>
     *      <li>信号、消息等事件的发布与接收，以及事件监听器的管理。</li>
     *  </ul>
     **/

    /**
     * <p><b>用途:发起流程实例<b></p>
     * @author <a href="mailto:blnp.yibin@qq.com">lyb</a>
     * @since 11:29 2025/4/29
     * @params [] 
     * @param  
     * @return void
    **/
    @Test
    public void test() {
        
        /*****根据流程定义key发起流程 *****/
        //根据流程定义key发起流程
        //runtimeService.startProcessInstanceByKey(String processDefinitionKey);
        
        //根据流程定义key及业务主键发起流程
        //runtimeService.startProcessInstanceByKey(String processDefinitionKey, String businessKey);
        
        //根据流程定义key及变量发起流程
        //runtimeService.startProcessInstanceByKey(String processDefinitionKey, Map<String, Object> variables);
        
        //根据流程定义key、业务主键及变量发起流程
        //runtimeService.startProcessInstanceByKey(String processDefinitionKey, String businessKey, Map<String, Object> variables);
        
        //根据流程定义key及租户ID发起流程
        //runtimeService.startProcessInstanceByKeyAndTenantId(String processDefinitionKey, String tenantId);
        
        //根据流程定义key、业务主键及租户ID发起流程
        //runtimeService.startProcessInstanceByKeyAndTenantId(String processDefinitionKey, String businessKey, String tenantId);
        
        //根据流程定义key、变量及租户ID发起流程
        //runtimeService.startProcessInstanceByKeyAndTenantId(String processDefinitionKey, Map<String, Object> variables, String tenantId);
        
        //根据流程定义key、业务主键、变量及租户ID发起流程
        //runtimeService.startProcessInstanceByKeyAndTenantId(String processDefinitionKey, String businessKey, Map<String, Object> variables, String tenantId);
        
        
        /*****根据流程定义ID发起流程*****/
        //根据流程定义ID发起流程
        //runtimeService.startProcessInstanceById(String processDefinitionId);
        
        //根据流程定义ID及业务主键发起流程
        //runtimeService.startProcessInstanceById(String processDefinitionId, String businessKey);
        
        //根据流程定义ID及变量发起流程
        //runtimeService.startProcessInstanceById(String processDefinitionId, Map<String, Object> variables);
        
        //根据流程定义ID、业务主键及变量发起流程
        //runtimeService.startProcessInstanceById(String processDefinitionId, String businessKey, Map<String, Object> variables);
        
        //根据流程定义ID发起流程，如果流程绑定了表单，使用该方法
        //runtimeService.startProcessInstanceWithForm(String processDefinitionId, String outcome, Map<String, Object> variables, String processInstanceName);
        
        
        /*****根据消息发起流程*****/
        //根据消息发起流程
        //runtimeService.startProcessInstanceByMessage(String messageName);
        
        //根据消息及租户ID发起流程
        //runtimeService.startProcessInstanceByMessageAndTenantId(String messageName, String tenantId);

        //根据消息、业务主键发起流程
        //runtimeService.startProcessInstanceByMessage(String messageName, String businessKey);
        
        //根据消息、业务主键及租户ID发起流程
        //runtimeService.startProcessInstanceByMessageAndTenantId(String messageName, String businessKey, String tenantId);
        
        //根据消息、变量发起流程
        //runtimeService.startProcessInstanceByMessage(String messageName, Map<String, Object> processVariables);
        
        //根据消息、变量及租户ID发起流程
        //runtimeService.startProcessInstanceByMessageAndTenantId(String messageName, Map<String, Object> processVariables, String tenantId);
        
        //根据消息、业务主键及变量发起流程
        //runtimeService.startProcessInstanceByMessage(String messageName, String businessKey, Map<String, Object> processVariables);
        
        //根据消息、业务主键、变量及租户ID发起流程
        //runtimeService.startProcessInstanceByMessageAndTenantId(String messageName, String businessKey, Map<String, Object> processVariables, String tenantId);
    }

    /**
     * <p><b>用途:唤醒一个等待状态的执行<b></p><br/>
     * <img src="https://free4.yunpng.top/2025/04/29/681049e858cb2.png" />
     * @author <a href="mailto:blnp.yibin@qq.com">lyb</a>
     * @since 11:38 2025/4/29
     * @params []
     * @param
     * @return void
    **/
    @Test
    public void test1() {
        /**
         *  RuntimeService接口提供了trigger()方法，用于唤醒一个等待状态的执行实例。该接口支持根据执行实例ID进行唤醒操作，还支持唤醒时传入流程变量、瞬时变量等参数。
         *
         *  //唤醒等待状态的执行
         *  void trigger(String executionId);
         *  //唤醒等待状态的执行，但是通过异步任务来执行
         *  void triggerAsync(String executionId);
         *  //唤醒等待状态的执行，同时传入新的流程变量
         *  void trigger(String executionId, Map<String, Object> processVariables);
         *  //唤醒等待状态的执行，同时传入新的流程变量，但是通过异步任务来执行
         *  void triggerAsync(String executionId, Map<String, Object> processVariables);
         *  //唤醒等待状态的执行，同时传入新的流程变量和瞬时变量
         *  void trigger(String executionId, Map<String, Object> processVariables, Map<String, Object> transientVariables);
         **/
        //部署流程
        Deployment deploy = repositoryService.createDeployment()
                .name("等待触发案例")
                .addClasspathResource("flow/waitStart.bpmn20.xml")
                .deploy();
        log.info("流程部署成功，部署ID为：{}", deploy.getId());
        //查询流程定义信息
        ProcessDefinition procDef = repositoryService.createProcessDefinitionQuery()
                .deploymentId(deploy.getId())
                .singleResult();
        //根据流程定义ID发起流程
        ProcessInstance procInst = runtimeService
                .startProcessInstanceById(procDef.getId());
        log.info("流程实例的ID为：{}", procInst.getId());
        //查询第一个任务
        Task firstTask = taskService.createTaskQuery()
                .processInstanceId(procInst.getId()).singleResult();
        log.info("第一个任务ID为：{}，任务名称为：{}", firstTask.getId(), firstTask.getName());
        taskService.setAssignee(firstTask.getId(), "huhaiqin");
        //完成第一个任务
        taskService.complete(firstTask.getId());
        log.info("第一个任务办理完成！");
        Execution execution = runtimeService.createExecutionQuery()
                .processInstanceId(procInst.getId()).onlyChildExecutions()
                .singleResult();
        log.info("当前执行实例ID为：{}", execution.getId());
        runtimeService.trigger(execution.getId());
        log.info("触发机器节点，继续流转！");
        //查询流程执行历史
        HistoricProcessInstance hisProcInst = historyService
                .createHistoricProcessInstanceQuery()
                .processInstanceId(procInst.getId())
                .singleResult();
        log.info("流程实例开始时间为：{}，结束时间为：{}",
                DateUtil.formatDateTime(hisProcInst.getStartTime()),
                DateUtil.formatDateTime(hisProcInst.getEndTime()));

        /**
         *  演示结果：
         *  2025-04-29 11:46:40.654  INFO 35108 --- [           main] c.b.n.f.api.runtime.RuntimeApiTest       : 流程部署成功，部署ID为：8f2f9392-24ac-11f0-b651-50ebf6ec8f6d
         *  2025-04-29 11:46:40.702  INFO 35108 --- [           main] c.b.n.f.api.runtime.RuntimeApiTest       : 流程实例的ID为：8f5bd3b6-24ac-11f0-b651-50ebf6ec8f6d
         *  2025-04-29 11:46:40.727  INFO 35108 --- [           main] c.b.n.f.api.runtime.RuntimeApiTest       : 第一个任务ID为：8f5f080b-24ac-11f0-b651-50ebf6ec8f6d，任务名称为：申请
         *  2025-04-29 11:46:40.808  INFO 35108 --- [           main] c.b.n.f.api.runtime.RuntimeApiTest       : 第一个任务办理完成！
         *  2025-04-29 11:46:40.817  INFO 35108 --- [           main] c.b.n.f.api.runtime.RuntimeApiTest       : 当前执行实例ID为：8f5bd3b7-24ac-11f0-b651-50ebf6ec8f6d
         *  2025-04-29 11:46:40.832  INFO 35108 --- [           main] c.b.n.f.api.runtime.RuntimeApiTest       : 触发机器节点，继续流转！
         *  2025-04-29 11:46:40.908  INFO 35108 --- [           main] c.b.n.f.api.runtime.RuntimeApiTest       : 流程实例开始时间为：2025-04-29 11:46:40，结束时间为：null
         **/
    }
}
